package com.xlf.service.base.manager;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xlf.common.core.constant.Constants;
import com.xlf.common.core.exception.BizException;
import com.xlf.common.core.util.BeanCopyUtils;
import com.xlf.common.core.util.StringUtils;
import com.xlf.pojo.base.*;
import com.xlf.service.base.mapper.*;
import com.xlf.service.base.pojo.vo.JudgeStatusVO;
import com.xlf.service.base.pojo.vo.LanguageVO;
import com.xlf.service.base.pojo.vo.ProblemDetailVO;
import com.xlf.service.base.pojo.vo.ProblemVO;
import com.xlf.service.system.service.impl.CommonUserVOService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Author xlf 2734029211@qq.com
 * @Date 2023/12/31 21:27
 * @Description: TODO
 * @Version 1.0
 */
@Service
public class ProblemCommonService {


    @Resource
    ProblemLanguageMapper problemLanguageMapper;

    @Resource
    LanguageMapper languageMapper;

    @Resource
    ProblemTagMapper problemTagMapper;

    @Resource
    TagMapper tagMapper;

    @Resource
    ProblemMapper problemMapper;

    @Resource
    DifficultyMapper difficultyMapper;

    @Autowired
    CommonUserVOService commonUserVOService;

    @Resource
    JudgeMapper judgeMapper;


    /**
     * 获取problem
     * @param id
     * @return
     */
    public Problem selectProblem(Long id) {

        Problem problem = problemMapper.selectById(id);

        if(problem == null)
            throw new BizException("题目不存在");

        if(problem.getStatus() == com.xlf.common.core.constant.Constants.EXCEPTION)
            throw new BizException("题目已下架");

        return problem;
    }


    /**
     * 获取题目语言Map
     * @param problemId
     * @return
     */
    public HashMap<String, LanguageVO> getLanguageVOHashMap(Long problemId) {

        //获取语言
        HashMap<String, LanguageVO> languageVOS = new HashMap<>();

        List<ProblemLanguage> languageList = problemLanguageMapper.selectList(new LambdaQueryWrapper<ProblemLanguage>()
                .eq(ProblemLanguage::getPid, problemId));

        if(StringUtils.isEmpty(languageList))
            return languageVOS;

        Set<Long> collect = languageList.stream().map(item -> item.getLid()).collect(Collectors.toSet());
        List<Language> languages = languageMapper
                .selectList(new LambdaQueryWrapper<Language>()
                        .in(Language::getId,collect)
                        .eq(Language::getStatus, com.xlf.common.core.constant.Constants.NORMAL));

        if(StringUtils.isEmpty(languages))
            return languageVOS;

        Map<Long, Language> stringMap = languages.stream().collect(Collectors.toMap(t -> t.getId(), t -> t));
        languageList.forEach(item -> {
            if(stringMap.containsKey(item.getLid())){
                LanguageVO languageVO = new LanguageVO();
                languageVO.setCode(item.getCode());
                languageVOS.put(stringMap.get(item.getLid()).getName(),languageVO);
            }
        });
        return languageVOS;
    }


    /**
     * 获取题目语言
     * @param problemId
     * @return
     */
    public List<Language> getProblemLanguageList(Long problemId,Consumer<LambdaQueryWrapper> consumer) {

        //获取语言
        List<ProblemLanguage> problemLanguages = problemLanguageMapper.selectList(new LambdaQueryWrapper<ProblemLanguage>()
                .eq(ProblemLanguage::getPid, problemId));

        if(StringUtils.isEmpty(problemLanguages))
            return new ArrayList<>();

        Set<Long> collect = problemLanguages.stream().map(item -> item.getLid()).collect(Collectors.toSet());

        LambdaQueryWrapper<Language> lambdaQueryWrapper = new LambdaQueryWrapper<Language>()
                .in(Language::getId, collect);
        consumer.accept(lambdaQueryWrapper);

        return Optional.ofNullable(languageMapper.selectList(lambdaQueryWrapper)).orElse(new ArrayList<>());
    }


    /**
     * 获取题目标签
     * @param problemId
     * @return
     */
    public List<Tag> getProblemTags(Long problemId) {
        return getProblemTags(problemId,null);
    }

    /**
     * 获取题目标签
     * @param problemId
     * @return
     */
    public List<Tag> getProblemTags(Long problemId, Consumer<LambdaQueryWrapper<Tag>> consumer) {

        //获取标签
        List<ProblemTag> problemTags = problemTagMapper.selectList(new LambdaQueryWrapper<ProblemTag>()
                .eq(ProblemTag::getProblemId, problemId)
                .select(ProblemTag::getTagId));

        if(StringUtils.isEmpty(problemTags)){
            return new ArrayList<>();
        }
        List<Long> collect = problemTags.stream().map(t -> t.getTagId()).collect(Collectors.toList());
        LambdaQueryWrapper<Tag> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Tag::getId,collect);
        if(consumer != null)
            consumer.accept(wrapper);

        return Optional.ofNullable(tagMapper.selectList(wrapper)).orElse(new ArrayList<>());

    }


    /**
     * 获取题目判题消息
     * @param problemId
     * @return
     */
    public List<JudgeStatusVO> judgeStatusVOList(Long problemId){
        return Optional.ofNullable(judgeMapper.selectStatusInfoByProblemId(problemId)).orElse(new ArrayList<>());
    }

    /**
     * 查询题目详情
     * @param problemId
     * @return
     */
    public ProblemDetailVO problemDetailVOCommander(Long problemId) {

        //获取题目
        Problem problem = selectProblem(problemId);

        //转换VO
        ProblemDetailVO problemDetailVO = toProblemDetailVO(problem);

        //获取难度
        if(!problemDetailVO.getAuth().equals(com.xlf.pojo.constant.Constants.ProblemAuth.CONTEST) &&
                problemDetailVO.getDifficultyId() != null)
            problemDetailVO.setDifficulty(difficultyMapper.selectById(problemDetailVO.getDifficultyId()));

        //获取标签
        problemDetailVO.setTagList(getProblemTags(problemDetailVO.getId(),(wrapper) -> wrapper.eq(Tag::getStatus, Constants.NORMAL)));

        //获取题目作者
        if(problemDetailVO.getAuthorId() != null)
            problemDetailVO.setAuthor(commonUserVOService.getUserInfo(problemDetailVO.getAuthorId()));

        //获取题目支持的语言
        problemDetailVO.setLanguageVOS(getLanguageVOHashMap(problemId));

        return problemDetailVO;
    }

    /**
     * 查询题目列表
     * @return
     */
    public List<ProblemVO> getProblemVOList(Consumer<LambdaQueryWrapper<Problem>> consumer) {

        LambdaQueryWrapper<Problem> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Problem::getStatus,Constants.NORMAL)
                .eq(Problem::getAuth, com.xlf.pojo.constant.Constants.ProblemAuth.PUBLIC.getCode());

        consumer.accept(wrapper);

        List<Problem> problemList = problemMapper.selectList(wrapper);

        if(StringUtils.isEmpty(problemList))
            return new ArrayList<>();

        List<ProblemVO> problemVOS = BeanUtil.copyToList(problemList, ProblemVO.class);

        problemVOS.forEach(item -> {
            item.setJudgeStatusVOS(judgeStatusVOList(item.getId()));
            item.setDifficulty(difficultyMapper.selectById(item.getDifficultyId()));
            item.setTagList(getProblemTags(item.getId(),(tagLambdaQueryWrapper)->{
                tagLambdaQueryWrapper.eq(Tag::getStatus, com.xlf.common.core.constant.Constants.NORMAL);
            }));
        });
        return problemVOS;
    }


    public ProblemDetailVO toProblemDetailVO(Problem problem) {
        ProblemDetailVO problemDetailVO = BeanCopyUtils.copyObject(problem, ProblemDetailVO.class);
        return problemDetailVO;
    }


    public class ProblemVOBuilder {

        private LambdaQueryWrapper<Problem> lambdaQueryWrapper;

        private Set<Long> problemIds;

        private boolean isEmpty;

        private boolean isPaging;

        public ProblemVOBuilder(){
            isEmpty = false;
            lambdaQueryWrapper = new LambdaQueryWrapper<>();
            problemIds = new HashSet<>();
        }

        public ProblemVOBuilder filterByDifficultyId(Long id){
            lambdaQueryWrapper.eq(StringUtils.isNotNull(id),Problem::getDifficultyId,id);
            return this;
        }

        public ProblemVOBuilder filterByTags(Set<Long> tagsId){
            if(isEmpty)
                return this;
            List<ProblemTag> problemTags = problemTagMapper.selectList(new LambdaQueryWrapper<ProblemTag>()
                            .select(ProblemTag::getProblemId)
                    .in(StringUtils.isNotEmpty(tagsId), ProblemTag::getTagId, tagsId));
            if(StringUtils.isEmpty(problemTags))
                isEmpty = true;
            else
                problemIds.addAll(problemTags.stream()
                        .map(item -> item.getProblemId())
                        .collect(Collectors.toSet()));

            return this;
        }

        public ProblemVOBuilder filterByTitle(String title){
            lambdaQueryWrapper.like(StringUtils.isNotEmpty(title),Problem::getTitle,title);
            return this;
        }



        public ProblemVOBuilder lambdaQueryWrapper(Consumer<LambdaQueryWrapper<Problem>> wrapperConsumer){
            wrapperConsumer.accept(lambdaQueryWrapper);
            return this;
        }

        public List<ProblemVO> builder(){

            if(isEmpty)
                return new ArrayList<>();
            lambdaQueryWrapper.eq(Problem::getStatus,Constants.NORMAL);
            lambdaQueryWrapper.in(Problem::getId,problemIds);
            List<Problem> problemList = problemMapper.selectList(lambdaQueryWrapper);
            if(StringUtils.isEmpty(problemList))
                return new ArrayList<>();
           return BeanUtil.copyToList(problemList, ProblemVO.class);

        }

    }

    public ProblemVOBuilder buildProblemVO() {
        return new ProblemVOBuilder();
    }




}
